package com.cskaoyan.javase._2inner._6lambda._3callback;

/**
 * Lambda表达式在实际开发中,往往是配合自然排序,文件过滤,Stream API等语法去使用
 * 在原理上,使用了一种被称之为"方法回调(callback)"的知识点
 *
 * 案例:
 *      现在上课,老师请小明童鞋回答问题
 *      小明会计算加法,但是不会其它的算术运算
 *      但是老师会随机提问各种算术问题
 *      于是小明就会求助别的童鞋:
 *          a.小红会乘法
 *          b.小黑会除法
 *          c.小蓝会减法
 *          ...
 *
 * @since 09:32
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        LittleMing m = new LittleMing();
        System.out.println("老师开始提问小明同学:");
        System.out.println("先提问加法问题:");
        m.answerAddQuestion(10, 10);

        System.out.println("继续提问乘法问题:");
        m.answerMultiplyQuestion(10, 10, new LittleRed());

        System.out.println("继续提问除法问题:");
        m.answerDivideQuestion(10, 10, new LittleBlack());


        System.out.println("继续提问减法问题:");
        m.answerQuestion(20, 10, (num1, num2) -> num1 - num2);

    }
}

// 小明类,小明会算加法,会回答老师问题
class LittleMing {
    public int add(int num1, int num2) {
        return num1 + num2;
    }

    // 自己能够回答老师的加法问题
    public void answerAddQuestion(int num1, int num2) {
        System.out.println("老师我知道,这个加法运算的结果是:" + add(num1, num2));
    }

    // 老师问乘法问题,求助于小红同学
    public void answerMultiplyQuestion(int num1, int num2, LittleRed r) {
        System.out.println("老师我知道,这个乘法运算的结果是:" + r.multiply(num1, num2));
    }

    // 老师问除法问题,求助于小黑同学
    public void answerDivideQuestion(int num1, int num2, LittleBlack b) {
        System.out.println("老师我知道,这个除法运算的结果是:" + b.divide(num1, num2));
    }

    /*
        上述小明求助于别的同学的方法
        方法实际上传入了一个对象,但更本质的,我们不是需要一个对象,是需要一个计算的"工具人"
        这个"工具人"只要会计算相关的运算就可以了,至于对象是什么,我们并不关心

        我们传入对象进一个方法,实质上想把方法所表示的计算规则传入方法
        那么在计算机领域,将一个方法作为参数,直接传递给另外一个方法,这种形式称之为"回调"
            作为参数传递的方法,称之为"回调方法"

        那么Java如何实现回调呢?
        Java是不支持直接将方法作为参数传递的
        但是可以间接实现"回调"
        使用"Lambda表达式 + 功能接口"传入方法
        虽然实际上是传入功能接口的对象,但本质上是传入了一个方法实现
        Lambda表达式所实现的功能接口中的回调方法,就是回调方法

     */


    // 方法需要一个计算规则,就传入接口计算规则的子类对象
    /*
        使用Lambda表达式实现"方法的回调"
        大幅度的增加了程序的扩展性
        使方法调用更加灵活
     */
    public void answerQuestion(int num1, int num2, ICalc calc) {
        System.out.println("老师我知道,这个运算的结果是:" + calc.ruler(num1, num2));
    }

}

// 上述提问方法,本质上需要一个计算规则,可以用功能接口中的抽象方法描述它
interface ICalc {
    // 该方法表示计算规则,它的实现用Lambda表达式
    double ruler(double num1, double num2);
}

// 小红会乘法
class LittleRed {
    public int multiply(int num1, int num2) {
        return num1 * num2;
    }
}

// 小黑会除法
class LittleBlack {
    public double divide(double num1, double num2) {
        return num1 / num2;
    }
}